#!/usr/bin/env python
import uuid

import openstack
from flask import current_app

from app import db
from app.models import rangeModel, userModel
from configs.get_config_info import env_config
from manage import app
from utils.crypto import decrypt_pw

openstack_config = env_config["USER_TO_OPENSTACK"]
range_config = {}

type_name_dict = {""}


def gen_id():
    return uuid.uuid1()


def add_range():
    global system_ranges
    for range in system_ranges:
        try:
            with app.app_context():
                # 创建靶场
                with db.auto_commit():
                    obj = rangeModel.Range(
                        name=range["name"],
                        type=range["type"],
                        difficulty=range["difficulty"],
                        describe=range["describe"],
                        user_id=2,
                        is_system=1,
                    )
                    rangeModel.db.session.add(obj)
                    rangeModel.db.session.commit()

                    # 插入关联表
                    rangeModel_obj = rangeModel.RangeLinkModule(
                        range_id=obj.id,
                        range_uuid=range["range_uuid"],
                        # type=range['type'],
                        user_id=1,
                    )
                    rangeModel.db.session.add(rangeModel_obj)
                    rangeModel.db.session.commit()

                    # 创建虚机
                    for vm_info in range["vm_args"]:
                        range_info = rangeModel.RangeLinkModule.query.filter_by(
                            range_uuid=vm_info["range_uuid"], user_id=1
                        ).first()
                        if not range_info:
                            print("range_info error")
                            break

                        # 保存拓扑图及各虚拟设备定位信息
                        rangeModel.Range.query.filter_by(id=range_info.range_id).update(
                            {
                                "topology_json": range["tp_json"],
                                "topology_img": range["tp_img"],
                            }
                        )

                        res = create_vm(vm_info)
                        if not res:
                            print("create {} error".format(vm_info["vm_name"]))

        except Exception as e:
            print(e)
    print("OK")


def create_vm(vm_info):
    project_id = userModel.User.query.filter_by(id=1).first().project_id
    flavor = openstack_config[project_id]["template_images_list"][vm_info["image"]][
        "flavor"
    ]
    ip = openstack_config[project_id]["template_images_list"][vm_info["image"]][
        "v4_fixed_ip"
    ]
    # 验证传入参数
    try:
        openstack_auth_config = decrypt_pw(env_config["OPENSTACK"]["auth"])
        conn = openstack.connect(
            auth=openstack_auth_config, auth_type=env_config["OPENSTACK"]["auth_type"]
        )
        openstack_image = conn.get_image(vm_info["image"])
        openstack_flavor = conn.get_flavor(flavor)
        if not all([openstack_image, openstack_flavor]):
            print("can't connect openstack image or flavor")
            return False

        with app.app_context():
            with db.auto_commit():
                obj = rangeModel.RangeVm(
                    vm_name=vm_info["vm_name"],
                    vm_uuid=vm_info["vm_uuid"],
                    range_uuid=vm_info["range_uuid"],
                    image=vm_info["image"],
                    flavor=flavor,
                    v4_fixed_ip=ip,
                    status=1,
                    user_id=2,
                )
                rangeModel.db.session.add(obj)
                rangeModel.db.session.commit()

    except Exception as e:
        print(e, "无法连接到云计算服务")
        return False
    return True


import json


def get_range(name, jsons, img, images=[], types=[], vm_name=[]):
    range_uuid = gen_id()
    vm_uuid_list = []
    vm_args = []
    vm_name_id_dict = {}
    for i in range(len(images)):
        vm_uuid = gen_id()
        dict1 = {}
        dict1["image"] = images[i]
        dict1["range_uuid"] = range_uuid
        dict1["vm_uuid"] = vm_uuid
        dict1["type"] = types[i]
        vm_name = range_config[images[i]]["name"]
        dict1["vm_name"] = vm_name
        vm_args.append(dict1)
        vm_name_id_dict[vm_name] = vm_uuid

    try:
        file_name = r"..\..\describe\ " + name + ".txt"
        with open(file_name, encoding="utf-8") as f:
            describe = f.read()
    except ValueError:
        describe = name

    thermal_power_args = {}
    thermal_power_args["name"] = name
    thermal_power_args["describe"] = describe
    thermal_power_args["difficulty"] = "2"
    thermal_power_args["task_id"] = "2"
    thermal_power_args["type"] = "1"
    thermal_power_args["range_uuid"] = (range_uuid,)
    thermal_power_args["vm_args"] = vm_args

    topology_json = json.loads(jsons, encoding="utf-8")
    for node in topology_json["nodeList"]:
        if "type" in node and "vm_uuid" in node:
            vm_uuid_list.append(vm_name_id_dict[node["name"]])
    thermal_power_args["tp_json"] = jsons % tuple(vm_uuid_list)
    thermal_power_args["tp_img"] = img
    return thermal_power_args


def get_json(range_json):
    topology_json = json.loads(range_json)
    if "nodeList" in topology_json:
        for node in topology_json["nodeList"]:
            if "type" in node and "vm_uuid" in node:
                node["vm_uuid"] = "%s"
                node["state"] = "created"
    topology_json = json.dumps(topology_json)

    return topology_json


def get_config_dict():
    project_id = list(current_app.config["USER_TO_OPENSTACK"].keys())[0]
    global range_config
    range_config = openstack_config[project_id]["template_images_list"]

    config_dict = {}
    for image, image_info in range_config.items():
        for key, value in image_info.items():
            if key == "name":
                range_name = value.split("场景")[0] + "场景"
                a = range_config[image]
                config_dict[range_name] = config_dict.get(range_name, [])
                config_dict[range_name].append({image: range_config[image]})
    return config_dict


if __name__ == "__main__":
    json_dict = {}
    image_dict = {}
    system_ranges = []
    range_model = []
    range_config_dict = get_config_dict()
    with app.app_context():
        range_list = rangeModel.Range.query.filter_by(is_system="0").all()
        range_exited_list = rangeModel.Range.query.filter_by(is_system="1").all()
        for rage in range_exited_list:
            range_model.append(rage.name)
        for ranges in range_list:
            if ranges.name in range_config_dict:
                json_dict[ranges.name] = ranges.topology_json
                image_dict[ranges.name] = ranges.topology_img
    for range_name, range_image_list in range_config_dict.items():
        if range_name in range_model:
            continue
        name = range_name
        jsons = get_json(json_dict[range_name])
        img = image_dict[range_name]
        types = []
        vm_name = []
        images = []
        for image_info in range_image_list:
            image_keys = list(image_info.keys())
            images.append(image_keys[0])
            types.append(image_info[image_keys[0]]["type"])
        system_ranges.append(get_range(name, jsons, img, images, types, vm_name))

    add_range()
